package com.youth.framework.core.web.listener;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ContextLoaderListener;

import com.youth.framework.core.SystemContext;
import com.youth.framework.util.Assert;
import com.youth.framework.util.ClassUtils;

/**
 * 实现从属性配置文件中加载与当前业务系统（web应用）相关的环境参数， 实现从远端的主控系统中获取与当前业务系统相关的环境参数，并覆盖本地同名的环境参数，
 * 业务处理逻辑可以通过 {@link SystemContext} 中的 getProperty 静态方法获取这些参数数据。
 * 
 * 实现从远端的主控系统获取当前业务系统的自描述信息，其中包括系统的环境变量信息，远端主控系统中 为当前系统设置的环境变量信息将会覆盖本地环境参数信息
 * 
 * 替代 {@link org.springframework.web.context.ContextLoaderListener} 完成 spring
 * 的上下文初始化工作
 * 
 * @author 
 * 
 */
public class SystemContextLoaderListener extends ContextLoaderListener
		implements ServletContextListener {
	// 初始需要使用的初始化文件在web.xml中的初始化环境参数名称
	public static final String CONTEXT_LOCATION_PARAM = "systemContextLocation";
	// 日志系统
	private static Log logger = LogFactory
			.getLog("SystemContextLoaderListener");

	/**
	 * WEB容器在关闭时，将触发此方法，用来释放自定义的资源数据，此处主要的作用是调用系统服务
	 * 通知平台系统，当前系统要注销，平台系统将更新与当前系统相关的状态信息
	 * 
	 * @param sce
	 *            WEB容器提供的事件参数
	 */
	public void contextDestroyed(ServletContextEvent sce) {
		if (logger.isDebugEnabled()) {
			logger.debug("SystemContextLoaderListener has destroyed");
		}

		super.contextDestroyed(sce);
	}

	/**
	 * WEB容器在启动时，将触发此方法，用来初始化业务系统数据，内容概括如下 1：加载本地环境变量
	 * 2：从平台加载环境变量并覆盖本地同名的环境变量（独立部署的情况下不会执行此操作）
	 * 3：初始化持久层的日志系统（日志系统继承自WEB容器，以方便统一管理） 4：初始化Spring框架的上下文（例如初始化bean等）
	 * 5：在控制台提示最终的关于信息，指示完成WEB容器关于当前系统的加载和初始化工作
	 */
	public void contextInitialized(ServletContextEvent sce) {
		ServletContext context = sce.getServletContext();
		String context_file = context.getInitParameter(CONTEXT_LOCATION_PARAM);
		Assert
				.hasText(
						context_file,
						"The Contex-Param which named 'systemContextLocation' was not confged correctly");

		loadLocalContext(context, context_file);

		if (logger.isDebugEnabled()) {
			logger.debug("SystemContextLoaderListener has initializing");
		}
		loadRemoteContext(context, SystemContext.getProperty("platform.url"));
		if (logger.isDebugEnabled()) {
			logger.debug("SystemContextLoaderListener has initialized");
		}

		// 设置MyBatis的日志系统为log4j
		org.apache.ibatis.logging.LogFactory.useLog4JLogging();

		// 基类上下文初始化（Spring 上下文处理）
		super.contextInitialized(sce);

		this.printSystemInfo();
	}

	@Override
	protected void customizeContext(ServletContext servletContext,
			ConfigurableWebApplicationContext applicationContext) {
		//
	}

	/**
	 * 从本地的上下文（属性文件）中加载系统上下文信息，这些信息可以 通过
	 * {@link com.kangli.framework.core.SystemContext} 的 getProperty 静态方法获取。
	 * 
	 * @param context
	 * @param context_file
	 */
	private void loadLocalContext(ServletContext context, String context_file) {
		Properties props = new Properties();
		if (context_file.startsWith("classpath:")) {
			context_file = context_file.substring(10);
			try {
				if (logger.isDebugEnabled()) {
					logger.debug("load context from local props file :"
							+ ClassUtils.getDefaultClassLoader().getResource(
									context_file));
				}
				props.load(ClassUtils.getDefaultClassLoader()
						.getResourceAsStream(context_file));
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			context_file = context.getRealPath(context_file);
			try {
				props.load(new FileInputStream(context_file));
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		try {
			Method method = SystemContext.class.getDeclaredMethod(
					"initEnviroment", Properties.class);
			method.setAccessible(true);
			method.invoke(SystemContext.class, props);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 从远端加载系统信息，这些信息包括系统的远端描述信息，远端环境变量，与系统相关的模块列表以及页面列表等
	 * 如果远端不可用（如主控平台本身不包含远端链接信息）
	 * 
	 * @param context
	 * @param platform_url
	 */
	private void loadRemoteContext(ServletContext context, String platform_url) {
		String system_key = SystemContext.getProperty("system.key");
		Assert.hasText(system_key,
				"The environment variable of 'system.key' must be provided");

	}

	private void printSystemInfo() {
	}
}
